#ifndef GRAPH_H_
#define GRAPH_H_

#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include <iostream>

using LinkId = int;
using NodeId = int;
using FlowId = int;

const int kMaxValue = 10000000;
const std::vector<int>Omega = {1, 2, 3};  //全部可用资源
const int limit_cost = 8;

struct Node{
    NodeId node_id;
    int node_type; //0代表不可中继节点，1代表高延迟节点，2代表低延迟节点
};

struct Link
{
    Link(NodeId source_id_in, NodeId ter_id_in,
         int cost_in, int delay_in, std::vector<int> C_units_in)
        : source_id(source_id_in),ter_id(ter_id_in), 
        cost(cost_in), delay(delay_in), C_units(C_units_in)
    {
        weight = 0;
        used = false;
    }
    ~Link(){}
   
    NodeId source_id;
    NodeId ter_id;
    int cost;
    int delay;
    std::vector<Link *> cousin;
    std::vector<int> C_units; //该线路上可用资源
    int weight;
    bool used;
};

struct Path
{
    Path(NodeId start=-1, NodeId end=-1)
    {
        cost = 0;
        delay =0;
        C_units = Omega;
        path_info.reserve(50);
        path_info.emplace_back(start);
        node_set.insert(end);
    }

    void clear()
    {
        path_info.clear();
        cost = 0;
        delay = 0;
        C_units = Omega;
    }

    void Print() const{
        std::cout<<"Path: ";
        for(NodeId i:path_info){
            std::cout<<i<<"  ";
        }
        std::cout<<"   Delay: "<<delay;
        std::cout<<"   NodesOn:";
        for(NodeId i:path_on){
            std::cout<<i<<"  ";
        }
        std::cout<<std::endl;
    };

    bool find(NodeId id)
    {
        return (node_set.find(id) != node_set.end());
    }

    friend bool operator<(const Path &a, const Path &b)
    {
        return a.cost < b.cost;
    }
    friend bool operator>(const Path &a, const Path &b)
    {
        return a.cost > b.cost;
    }

    std::vector<NodeId> path_info;
    std::vector<NodeId> path_on;
    //std::vector<Link *> path_link;
    //NodeId curNode;
    int cost;
    int delay;
    std::vector<int> C_units; // 该路径上使用的资源
    std::unordered_set<NodeId> node_set;
};



struct Lable{
    int weight;
    LinkId Edge_id;
    std::vector<int> CU;  //使用的资源

    Lable(){}
    Lable(int weight_in, LinkId Edge_id_in, std::vector<int> CU_in):
    weight(weight_in), Edge_id(Edge_id_in), CU(CU_in){}
};

class Graph
{
public:
    explicit Graph(int size) : size_(size), node_to_egress_links_(size+1,std::vector<Link*>{}),nodes_type_(size+1) 
    {
        links_.reserve(size_ * size_ *10);
        links_black_.reserve(size_*size_*10);
        links_blue_.reserve(size_*size_*10);
    }

    void addNodes(NodeId id, int type){
        if(id > size_){
            std::cout<<"节点超出";
            return;
        }
        nodes_type_[id] = type;
    }

    void addLinks(NodeId source_id, NodeId ter_id,
         int cost, int delay, std::vector<int> C_units ){
            if(source_id>size_||ter_id>size_){
                std::cout<<"节点超出";
                return;
            }
            Link *tmp=new Link(source_id, ter_id, cost, delay, C_units);
            Link *tmp_rev=new Link(ter_id,source_id,cost,delay,C_units);
            links_.emplace_back(tmp);
            links_.emplace_back(tmp_rev);
            int type = GetNodeType(ter_id);
            if(type==2){
                tmp=new Link(source_id, ter_id,-1,delay+10,C_units);
                links_black_.emplace_back(tmp);
            }else if(type==1){
                tmp=new Link(source_id, ter_id,-1,delay+100,C_units);
                links_blue_.emplace_back(tmp);
            }
         }
    
    //构建节点未开启时的Graph
    void makeGraph(){
        for(Link *lk:links_){
            NodeId source = lk->source_id;
            node_to_egress_links_[source].emplace_back(lk);
        }
    }


    //构建低延迟节点开启后的Graph
    void makeGraph_black(){
        for(int i = 0; i<links_black_.size();i++){
            Link* link = links_black_[i];
            NodeId source = link->source_id;
            node_to_egress_links_[source].emplace_back(link);
        }
    }

    //构建高延迟节点开启后的Graph
    void makeGraph_blue(){
        for(int i = 0; i<links_blue_.size();i++){
            Link* link = links_blue_[i];
            NodeId source = link->source_id;
            node_to_egress_links_[source].emplace_back(link);
        }
    }

    void Check(){
        std::cout<<"size:"<<size_<<std::endl;
        std::cout<<"Links:"<<std::endl;
        for(Link *lk:links_){
            std::cout<<lk->source_id<<' '<<lk->ter_id<<' '<<lk->cost<<' '<<lk->delay<<std::endl;
        }
        for(int i=1;i<=size_;i++){
            std::cout<<i<<':'<<std::endl;
            for(Link *lk:node_to_egress_links_[i]){
                std::cout<<lk->source_id<<' '<<lk->ter_id<<std::endl;
            }
            std::cout<<std::endl;
        }
    }

    int NodeSize() const
    {
        return size_;
    }

    int LinkSize() const
    {
        return links_.size();
    }

   
   std::vector<Link *> GetEgressLinks(NodeId node) const
    {
        return node_to_egress_links_.at(node);
    }

   
    int GetNodeType(NodeId n)
    {
        return nodes_type_[n];
    }
    

private:
    std::vector<Link *> links_; //记录所有未开启节点的边
    std::vector<Link *> links_black_; //记录开启低延迟节点的边
    std::vector<Link *> links_blue_; //记录开启高延迟节点的边
    std::vector<int> nodes_type_; // 记录不同节点的类型
    std::vector<std::vector<Link *>> node_to_egress_links_;
    int size_;
    Graph(const Graph &) = delete;
    Graph &operator=(const Graph &) = delete;
};



struct Flow
{
    Flow() {}
    Flow( NodeId start_in, NodeId end_in,FlowId id_in=0,
         int lb=0,int ub=kMaxValue) :  id(id_in),start(start_in),end(end_in),delay_lb(lb),delay_ub(ub){}
    void Print() const{};
    FlowId id;
    NodeId start;
    NodeId end;
    int delay_lb;
    int delay_ub;
};

class Demand
{
public:
    // Read network flows from a file.
    explicit Demand(const std::string &file_path);

    int NumFlows()
    {
        return flows_.size();
    }
    const Flow &GetFlow(FlowId id)
    {
        return flows_.at(id);
    }

private:
    std::vector<Flow> flows_;
};

#endif 
